home *** CD-ROM | disk | FTP | other *** search
/ Aminet 33 / Aminet 33 - October 1999.iso / Aminet / dev / cross / ava-0.2.5.lha / ava-0.2.5 / src / Object.C < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-23  |  25.5 KB  |  841 lines

  1. /*
  2.   Object.C
  3.   
  4.   Object/Executable Code Generator and Parser
  5.   Uros Platise, dec. 1998
  6. */
  7.  
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include "Lexer.h"
  13. #include "Global.h"
  14. #include "Preproc.h"
  15. #include "Syntax.h"
  16. #include "Symbol.h"
  17. #include "Segment.h"
  18. #include "Keywords.h"
  19. #include "Object.h"
  20. #include "Reports.h"
  21.  
  22. /*
  23.   AVA Object Version; Major=1, Minor=1 
  24.   Two objects are compatabile as long as major numbers are the
  25.   same.
  26.   
  27.   Changes: 1.1 -> 1.2
  28.   ===================
  29.    Obj: 1.1/1.2     * added: listing enabled option for individual 
  30.                       file (as specified durring assemble time)
  31.  
  32.    Obj: 2.x/3.x     * header index was moved to the near end of the file
  33.                       and CRC32 error detection is included.
  34. */
  35.  
  36. #define OBJ_VERSION_MAJOR    3
  37. #define OBJ_VERSION_MINOR    0
  38.  
  39. char* obj_magic = "avaobj";
  40. char* exe_magic = "avaexe";
  41.  
  42. /* Besides instruction, reference to source code is given - with
  43.    line number. If this number equals zero, current file
  44.    was included by the original source. For include files,
  45.    lists are never generated.
  46. */
  47. #define LST_NOSRC    0
  48.  
  49. /* DEFAULT executable output filename, if extra switch -o filename
  50.    is not given, is defined by the following macro. */
  51.    
  52. #define DEFAULT_EXE    "a.out"   
  53. #define TMP_DIR        "/tmp"
  54.  
  55.  
  56. /*
  57.   The 32 bit CRC table.
  58. */
  59. const long int TCRC::crc32_table[] = {
  60.   0x000000000, 0x077073096, 0x0ee0e612c, 0x0990951ba,
  61.   0x0076dc419, 0x0706af48f, 0x0e963a535, 0x09e6495a3,
  62.   0x00edb8832, 0x079dcb8a4, 0x0e0d5e91e, 0x097d2d988,
  63.   0x009b64c2b, 0x07eb17cbd, 0x0e7b82d07, 0x090bf1d91,
  64.  
  65.   0x01db71064, 0x06ab020f2, 0x0f3b97148, 0x084be41de,
  66.   0x01adad47d, 0x06ddde4eb, 0x0f4d4b551, 0x083d385c7,
  67.   0x0136c9856, 0x0646ba8c0, 0x0fd62f97a, 0x08a65c9ec,
  68.   0x014015c4f, 0x063066cd9, 0x0fa0f3d63, 0x08d080df5,
  69.  
  70.   0x03b6e20c8, 0x04c69105e, 0x0d56041e4, 0x0a2677172,
  71.   0x03c03e4d1, 0x04b04d447, 0x0d20d85fd, 0x0a50ab56b,
  72.   0x035b5a8fa, 0x042b2986c, 0x0dbbbc9d6, 0x0acbcf940,
  73.   0x032d86ce3, 0x045df5c75, 0x0dcd60dcf, 0x0abd13d59,
  74.  
  75.   0x026d930ac, 0x051de003a, 0x0c8d75180, 0x0bfd06116,
  76.   0x021b4f4b5, 0x056b3c423, 0x0cfba9599, 0x0b8bda50f,
  77.   0x02802b89e, 0x05f058808, 0x0c60cd9b2, 0x0b10be924,
  78.   0x02f6f7c87, 0x058684c11, 0x0c1611dab, 0x0b6662d3d,
  79.  
  80.   0x076dc4190, 0x001db7106, 0x098d220bc, 0x0efd5102a,
  81.   0x071b18589, 0x006b6b51f, 0x09fbfe4a5, 0x0e8b8d433,
  82.   0x07807c9a2, 0x00f00f934, 0x09609a88e, 0x0e10e9818,
  83.   0x07f6a0dbb, 0x0086d3d2d, 0x091646c97, 0x0e6635c01,
  84.  
  85.   0x06b6b51f4, 0x01c6c6162, 0x0856530d8, 0x0f262004e,
  86.   0x06c0695ed, 0x01b01a57b, 0x08208f4c1, 0x0f50fc457,
  87.   0x065b0d9c6, 0x012b7e950, 0x08bbeb8ea, 0x0fcb9887c,
  88.   0x062dd1ddf, 0x015da2d49, 0x08cd37cf3, 0x0fbd44c65,
  89.  
  90.   0x04db26158, 0x03ab551ce, 0x0a3bc0074, 0x0d4bb30e2,
  91.   0x04adfa541, 0x03dd895d7, 0x0a4d1c46d, 0x0d3d6f4fb,
  92.   0x04369e96a, 0x0346ed9fc, 0x0ad678846, 0x0da60b8d0,
  93.   0x044042d73, 0x033031de5, 0x0aa0a4c5f, 0x0dd0d7cc9,
  94.  
  95.   0x05005713c, 0x0270241aa, 0x0be0b1010, 0x0c90c2086,
  96.   0x05768b525, 0x0206f85b3, 0x0b966d409, 0x0ce61e49f,
  97.   0x05edef90e, 0x029d9c998, 0x0b0d09822, 0x0c7d7a8b4,
  98.   0x059b33d17, 0x02eb40d81, 0x0b7bd5c3b, 0x0c0ba6cad,
  99.  
  100.   0x0edb88320, 0x09abfb3b6, 0x003b6e20c, 0x074b1d29a,
  101.   0x0ead54739, 0x09dd277af, 0x004db2615, 0x073dc1683,
  102.   0x0e3630b12, 0x094643b84, 0x00d6d6a3e, 0x07a6a5aa8,
  103.   0x0e40ecf0b, 0x09309ff9d, 0x00a00ae27, 0x07d079eb1,
  104.  
  105.   0x0f00f9344, 0x08708a3d2, 0x01e01f268, 0x06906c2fe,
  106.   0x0f762575d, 0x0806567cb, 0x0196c3671, 0x06e6b06e7,
  107.   0x0fed41b76, 0x089d32be0, 0x010da7a5a, 0x067dd4acc,
  108.   0x0f9b9df6f, 0x08ebeeff9, 0x017b7be43, 0x060b08ed5,
  109.  
  110.   0x0d6d6a3e8, 0x0a1d1937e, 0x038d8c2c4, 0x04fdff252,
  111.   0x0d1bb67f1, 0x0a6bc5767, 0x03fb506dd, 0x048b2364b,
  112.   0x0d80d2bda, 0x0af0a1b4c, 0x036034af6, 0x041047a60,
  113.   0x0df60efc3, 0x0a867df55, 0x0316e8eef, 0x04669be79,
  114.  
  115.   0x0cb61b38c, 0x0bc66831a, 0x0256fd2a0, 0x05268e236,
  116.   0x0cc0c7795, 0x0bb0b4703, 0x0220216b9, 0x05505262f,
  117.   0x0c5ba3bbe, 0x0b2bd0b28, 0x02bb45a92, 0x05cb36a04,
  118.   0x0c2d7ffa7, 0x0b5d0cf31, 0x02cd99e8b, 0x05bdeae1d,
  119.  
  120.   0x09b64c2b0, 0x0ec63f226, 0x0756aa39c, 0x0026d930a,
  121.   0x09c0906a9, 0x0eb0e363f, 0x072076785, 0x005005713,
  122.   0x095bf4a82, 0x0e2b87a14, 0x07bb12bae, 0x00cb61b38,
  123.   0x092d28e9b, 0x0e5d5be0d, 0x07cdcefb7, 0x00bdbdf21,
  124.  
  125.   0x086d3d2d4, 0x0f1d4e242, 0x068ddb3f8, 0x01fda836e,
  126.   0x081be16cd, 0x0f6b9265b, 0x06fb077e1, 0x018b74777,
  127.   0x088085ae6, 0x0ff0f6a70, 0x066063bca, 0x011010b5c,
  128.   0x08f659eff, 0x0f862ae69, 0x0616bffd3, 0x0166ccf45,
  129.  
  130.   0x0a00ae278, 0x0d70dd2ee, 0x04e048354, 0x03903b3c2,
  131.   0x0a7672661, 0x0d06016f7, 0x04969474d, 0x03e6e77db,
  132.   0x0aed16a4a, 0x0d9d65adc, 0x040df0b66, 0x037d83bf0,
  133.   0x0a9bcae53, 0x0debb9ec5, 0x047b2cf7f, 0x030b5ffe9,
  134.  
  135.   0x0bdbdf21c, 0x0cabac28a, 0x053b39330, 0x024b4a3a6,
  136.   0x0bad03605, 0x0cdd70693, 0x054de5729, 0x023d967bf,
  137.   0x0b3667a2e, 0x0c4614ab8, 0x05d681b02, 0x02a6f2b94,
  138.   0x0b40bbe37, 0x0c30c8ea1, 0x05a05df1b, 0x02d02ef8d
  139. };
  140.  
  141. void TCRC::Update(unsigned char byte){
  142.   crc32 = crc32_table[ (unsigned char)(crc32^((unsigned long)byte)) ] ^ 
  143.                          ((crc32>>8) & 0x00FFFFFF);
  144. }
  145.  
  146.  
  147. /*
  148.   PASS1/2 functions for intermediate OBJ-EXE language.
  149. */
  150.  
  151. /* GENERAL OPERAND, QOPERAND IMPLEMENTATION */
  152.  
  153. void TObject::outOperand(const char* operand, 
  154.                          char operandType=OBJ_OPERAND_CODE){
  155.   CRCprintf(outfd,"%c{%s}\n",operandType, operand);
  156. }
  157. void TObject::outOperand(long lval, char operandType=OBJ_OPERAND_CODE){
  158.   CRCprintf(outfd,"%c{$%lx}\n",operandType, lval);
  159. }
  160. void TObject::outStringOperand(const char *s){CRCprintf(outfd,"q{\"%s\"}\n",s);}
  161.  
  162. void TObject::outCode(unsigned char byteC){
  163.   char buf[8]; sprintf(buf,"%2.2x",byteC); 
  164.   if (seg_output()!=NULL){seg_output->Push(buf);}
  165.   if (!uAsm_exe){CRCprintf(outfd,"\"%s\"\n",buf);}
  166.   reports.listing.Codecat(buf);
  167. }
  168. void TObject::outCode(unsigned  int wordC){
  169.   char pbuf[10]; sprintf(pbuf,"%8.8lx",(long)wordC);
  170.   char* buf = &pbuf[4];
  171.   if (seg_output()!=NULL){seg_output->Push(buf);}
  172.   if (!uAsm_exe){CRCprintf(outfd,"\"%s\"\n",buf);}
  173.   reports.listing.Codecat(buf);
  174. }
  175. void TObject::outCode(unsigned long longC){
  176.   char buf[14]; sprintf(buf,"%8.8lx",longC);
  177.   if (seg_output()!=NULL){seg_output->Push(buf);}  
  178.   if (!uAsm_exe){CRCprintf(outfd,"\"%s\"\n",buf);}
  179.   reports.listing.Codecat(buf);
  180. }
  181. void TObject::outCompiled(const char* compiled_code){
  182.   CRCprintf(outfd,"\"%s\"\n",compiled_code);
  183. }
  184.  
  185. /* INSTRUCTIONs and KEYWORDs */
  186.  
  187. void TObject::outInstruction(int instNo, bool insertRef=true){
  188.   if (insertRef==true){outSrcLine();}
  189.   CRCprintf(outfd,"i{$%x}\n", instNo);
  190. }
  191. void TObject::outKeyword(int keyNo, bool insertRef=true){
  192.   if (insertRef==true){outSrcLine();}
  193.   CRCprintf(outfd,"k{$%x}\n", keyNo);
  194. }      
  195.  
  196.  
  197. /* OBJECT AND EXE STRUCTURE */
  198.  
  199. void TObject::createObjHeader(){
  200.   char buf [LX_LINEBUF];
  201.   CRCprintf(outfd, "%s %d %d\n%s",
  202.     obj_magic,OBJ_VERSION_MAJOR,OBJ_VERSION_MINOR,
  203.     archp->Device(buf));
  204.     
  205.   
  206. }
  207. void TObject::outHeaderIndex(){
  208.   CRCprintf(outfd, "%c{0x%8.8lx}\n", OBJ_HEADERIDX, obj_header_seek);
  209. }
  210. void TObject::createExeHeader(){
  211.   if (uAsm_exe){
  212.     CRCprintf(outfd,"[code]\n");
  213.   }else{CRCprintf(outfd, "%s %d %d\n",
  214.                 exe_magic, OBJ_VERSION_MAJOR, OBJ_VERSION_MINOR);}
  215. }
  216. void TObject::outTerminator(){if(!uAsm_exe){CRCprintf(outfd,"T\n");}}
  217. void TObject::outEndofFile(){
  218.   if(uAsm_exe){
  219.     CRCprintf(outfd,"[end]\n");
  220.   }else{
  221.     CRCprintf(outfd, "%c{0x%8.8lx}\n", OBJ_ENDOFFILE, crc.Val());
  222.   }
  223. }
  224.  
  225.  
  226. /* SYMBOLs */
  227.  
  228. void TObject::outSymbolData(){CRCprintf(outfd,"Y\n");}
  229.  
  230.  
  231. /* SEGMENTs */
  232.  
  233. void TObject::outSegmentData(int segInfoNo){
  234.   CRCprintf(outfd,"S{$%x}\n",segInfoNo);}
  235. void TObject::outSegment(int segNo){
  236.   if(!uAsm_exe)CRCprintf(outfd,"s{$%x}\n",segNo);
  237. }
  238.  
  239. void TObject::outPCMarker(const char* marker){
  240.   if (uAsm_exe){throw generic_error("outPCMarker: Internal Error.");}
  241.   else{outOperand(marker, OBJ_OPERAND_PCMARKER);}
  242. }
  243. void TObject::outPCMarker(long marker, int segNo=0){  
  244.   assert(segNo!=0);
  245.   if (seg_output()!=NULL){seg_output->SetAddress(marker);}
  246.   if (!uAsm_exe){outOperand(marker, OBJ_OPERAND_PCMARKER);}
  247. }
  248.  
  249.  
  250. /* SOURCE CODE REFERENCES */
  251.  
  252. void TObject::outCRef(long ref){
  253.   if(!uAsm_exe)outOperand(ref, OBJ_CREF);
  254. }
  255. void TObject::outListing(){
  256.   if(!uAsm_exe && reports.listing.IsEnabled()){
  257.     CRCprintf(outfd,"%c\n", OBJ_LISTING_ENABLED);}
  258. }
  259.  
  260. /* outSrcLine(): PASS1 output */
  261. void TObject::outSrcLine(){
  262.   if (oldSrcLine!=preproc.line() && reports.listing.IsEnabled()){
  263.     oldSrcLine=preproc.line();
  264.     if (preproc.firstSource()==false){oldSrcLine=LST_NOSRC;}   
  265.     CRCprintf(outfd,"l{$%lx}\n",oldSrcLine);
  266.   }
  267. }
  268. void TObject::outAsmSource(const char* src){
  269.   if (!uAsm_exe && reports.listing.IsEnabled()){
  270.     CRCprintf(outfd, "R{\"%s\"}\n", src);}
  271. }  
  272. /* outSrcLine(): obji2objii and obj2exe output */
  273. void TObject::outSrcLine(long srcLine){
  274.   if (!uAsm_exe)CRCprintf(outfd,"l{$%lx}\n",srcLine);}
  275.  
  276.  
  277. /*
  278.   The cprintf 
  279.   Print and calculate CRC32
  280. */
  281. void TObject::CRCprintf(FILE* fd, const char* fmt, ...){
  282.   char buf [LX_STRLEN], *p=buf;
  283.   va_list ap;
  284.   va_start(ap,fmt); 
  285.   vsprintf(buf,fmt,ap);
  286.   fputs(buf,fd);
  287.   while(*p!=0){crc.Update(*p++);}
  288.   va_end(ap); 
  289. }
  290.  
  291.  
  292. /*
  293.   Segment Output Functions
  294. */
  295.  
  296. TSegmentOutput::TSegmentOutput(int _segNo, long _size, long _offset):
  297.   CRef(0), segNo(_segNo), size(_size), used(0), addr(0), offset(_offset), 
  298.   bp(NULL) {
  299.   buf = new char[2*size];
  300. }
  301.  
  302. void TSegmentOutput::Push(const char* code){
  303.   if (copySeg()!=NULL){copySeg->Push(code);}
  304.   assert(addr>=0 && addr<size);
  305.   assert(bp!=NULL);
  306.   while(*code!=0){*bp++ = *code++; used++;}
  307. }
  308.  
  309. #define MAX_BPL    0x10    /* max bytes per line */
  310.  
  311. void TSegmentOutput::Flush(FILE* outfd){
  312.   /* skip abstract segments */
  313.   if (segment.isAbstract(segNo)){return;}
  314.  
  315.   /* calc. alignment for the uIsp compatibility only! */
  316.   int alignBytes=segment.TellAlign(segNo)-(size%segment.TellAlign(segNo));
  317.   alignBytes%=segment.TellAlign(segNo);
  318.  
  319.   /* calculate CRC (and count align. bytes also) */
  320.   TCRC crc;
  321.   for (long i=0; i<(2*size); i++){crc.Update(buf[i]);} /* out size bytes */
  322.   for (int  i=0; i<(2*alignBytes); i++){crc.Update('0');}  
  323.  
  324.   /* Output Segment Header */  
  325.   fprintf(outfd, "@%s,%lx %8.8lx", 
  326.     segment.TellBaseSegment(segNo), offset, crc.Val());
  327.           
  328.   if (used!=(size<<1)){
  329.     reports.Warnning("Bad segment output buffer for the `%s'\n"
  330.       "Status: (used=$%lx, size=$%lx) nibbles",
  331.       segment.TellSegmentName(segNo), used, size<<1);
  332.     throw generic_error("FATAL INTERNAL ERROR.\n");
  333.   }  
  334.   char* p = buf;
  335.   for (long i=0; i<size; i++){    
  336.     if ((i%MAX_BPL)==0){fputc('\n', outfd);}
  337.     fputc(*p++, outfd); fputc(*p++, outfd);
  338.   }
  339.   if (((size-1)%MAX_BPL) || (size-1)==0){fputc('\n', outfd);}
  340.   
  341.   /* Due to the uIsp compatibility, output align. characters */
  342.   if (alignBytes > 0){
  343.     for (int i=0; i<alignBytes; i++){fprintf(outfd, "00");}
  344.     fputc('\n',outfd);
  345.   }
  346. }
  347.  
  348. void TObject::CreateOutputBuffers(){
  349.   /* create output pipes for base segments only */
  350.   int idx;
  351.   long default_size;
  352.   for (idx=1; idx < segment.TellNoSegments(); idx++){
  353.     if (!segment.isEnabled(idx)){
  354.       default_size=0;
  355.     } else {
  356.       default_size=segment.TellSize(idx);
  357.     }     
  358.     seg_output_table [idx] = new TSegmentOutput(idx, default_size,
  359.       segment.TellAbsolute(idx));    
  360.   }  
  361.   /* because all pipes are open, we can set mirrors */
  362.   int mirrorSegNo;
  363.   for (idx=1; idx < segment.TellNoSegments(); idx++){
  364.     mirrorSegNo = segment.TellMirror(idx);
  365.     if (mirrorSegNo!=-1){
  366.       if (segment.isEnabled(mirrorSegNo)){
  367.         seg_output_table[idx]->SetMirror(seg_output_table[mirrorSegNo]);
  368.       }
  369.     }
  370.   }
  371. }
  372.  
  373. /*
  374.   PARSER and GENERATOR for PASS1 to PASS2
  375. */
  376. void TObject::obji2objii(const char* src){
  377.   int opCount=0;
  378.   int segNo, instr, key, i, cpylen = strlen(OBJ_COPY_OPERANDS);
  379.   long operand=0, currentLine=1;
  380.   static char* copy_op = OBJ_COPY_OPERANDS;
  381.   bool enableSegment=true;
  382.   
  383.   /* halt on macros and non-external macros */
  384.   symbol.haltOnMacro();
  385.   syntax.haltOnInvalidMacros();
  386.   
  387.   while(lexer._gettoken()){
  388.     if (lxP->type==TlxData::NEWLINE){continue;}
  389.     if (lxP->type==TlxData::STRING && lxP->string[1]==0){
  390.  
  391.       switch(lxP->string[0]){
  392.       
  393.       /* operand: increment operand count per instruction */
  394.       case OBJ_OPERAND_CODE: 
  395.         if (enableSegment==false){skipOperand();break;}
  396.         loadOperand(opCount==operand_stack.capacity());
  397.     opCount++; 
  398.         break;
  399.  
  400.       case OBJ_INSTRUCTION: /* instruction */
  401.         instr=(int)loadArgument();
  402.     if (enableSegment==false){break;}
  403.     preproc.mark(currentLine,src);
  404.         if (opCount!=operand_stack.capacity()){outInstruction(instr,false);}
  405.     else{archp->Translate(instr);}          
  406.     if (operandStacksEmpty()==false){
  407.       throw syntax_error("obj2exe: Operand stack is not empty.");}
  408.     opCount=0;
  409.         break;
  410.  
  411.       case OBJ_KEYWORD:
  412.         key=(int)loadArgument();
  413.     if (enableSegment==false){break;}
  414.     preproc.mark(currentLine,src);
  415.         if (opCount!=operand_stack.capacity()){outKeyword(key,false);}
  416.     else{keywords.Translate(key);}
  417.     if (operandStacksEmpty()==false){
  418.       throw syntax_error("obj2exe: Operand stack is not empty.");}
  419.     opCount=0;
  420.         break;
  421.  
  422.       case OBJ_SEGMENT: /* segment */        
  423.         segNo = (int)loadArgument();
  424.     enableSegment = segment.isEnabled(segNo);
  425.     if (enableSegment==true){outSegment(segNo);}
  426.         break;
  427.  
  428.       case OBJ_OPERAND_PCMARKER: /* PC marker */
  429.         loadOperand(false, 'M');
  430.     break;
  431.  
  432.       case OBJ_ASMREF: /* assembler listing */
  433.         currentLine=loadArgument();
  434.     if (enableSegment==true){outSrcLine(currentLine);}
  435.     break;
  436.                 
  437.       default:
  438.         for (i=0;i<cpylen;i++){
  439.       if (lxP->string[0]==copy_op[i]){
  440.         operand=loadArgument();
  441.         if (enableSegment==true){outOperand(operand,copy_op[i]);break;}}
  442.     }
  443.     if (i==cpylen){
  444.           throw syntax_error("Unsupported object directive: ",lxP->string);}
  445.     break;
  446.       }
  447.     }
  448.     else if (lxP->type==TlxData::QSTRING){
  449.       outCompiled(lxP->string);
  450.     }
  451.     else{throw syntax_error("obji2objii: Object file is corrupted.");}
  452.   }
  453. }
  454.  
  455. /*
  456.   Load operand on stack - if operand is a not of lval type, 
  457.   push all the previously stacked operands to the output.
  458.   
  459.   Return true, if operand was pushed on stack, oterhwise false
  460. */
  461. bool TObject::loadOperand(bool onStack, char operandType=OBJ_OPERAND_CODE){
  462.   bool retVal=false;
  463.   /* expect { */
  464.   GET_TOKEN; if (lxP->type!=TlxData::CONTROL||lxP->string[0]!='{'){
  465.     throw syntax_error("loadOperand(): Object file is corrupted.");}
  466.   GET_TOKEN;
  467.   syntax.Parse_GAS(1);
  468.   if (gas.status==TGAS::Solved && onStack==true){ /* push operand on stack */
  469.     operand_stack.push(gas.result()); retVal=true;
  470.   }else{                /* unroll stack */
  471.     int items = operand_stack.capacity();
  472.     for (int i=0; i<items; i++){outOperand(operand_stack[i],operandType);}
  473.     operand_stack.clear();
  474.     outOperand(gas.eqstr,operandType);
  475.   }
  476.   if (lxP->type!=TlxData::CONTROL||lxP->string[0]!='}'){
  477.     throw syntax_error("loadOperand(): Object file is corrupted.");}
  478.   return retVal;
  479. }
  480.  
  481. void TObject::loadStringOperand(){
  482.   /* expect { */
  483.   GET_TOKEN; if (lxP->type!=TlxData::CONTROL||lxP->string[0]!='{'){
  484.     throw syntax_error("loadStringOperand():1: Object file is corrupted.");}
  485.   GET_TOKEN;
  486.   if (lxP->type!=TlxData::QSTRING){
  487.     throw syntax_error("loadStringOperand():2: Object file is corrupted.");}
  488.   pushStringOperand(lxP->string);
  489.   GET_TOKEN; if (lxP->type!=TlxData::CONTROL||lxP->string[0]!='}'){
  490.     throw syntax_error("loadStringOperand():3: Object file is corrupted.");}  
  491. }
  492.  
  493. void TObject::skipOperand(){
  494.   WHILE_TOKEN{
  495.     if (lxP->type==TlxData::CONTROL && lxP->string[0]=='}'){break;}}
  496. }
  497.  
  498. long TObject::loadArgument(){
  499.   /* expect { */
  500.   GET_TOKEN; if (lxP->type!=TlxData::CONTROL||lxP->string[0]!='{'){
  501.     throw syntax_error("loadArgument():1: Object file is corrupted.");}
  502.   GET_TOKEN;
  503.   syntax.Parse_GAS();
  504.   if (gas.status != TGAS::Solved){
  505.     throw syntax_error("loadArgument():2: Object file is corrupted.");}
  506.   if (lxP->type!=TlxData::CONTROL||lxP->string[0]!='}'){
  507.     throw syntax_error("loadArgument():3: Object file is corrupted.");}
  508.   return gas.result();
  509. }
  510.  
  511. void TObject::assemble(const char* outfile, const char* asm_source){
  512.   char sourceFile[PPC_MAXFILELEN];
  513.   char tmpFileName[PPC_MAXFILELEN];
  514.   char objectFileName[PPC_MAXFILELEN];
  515.   
  516.   uAsm_exe = false;
  517.   assert(asm_source!=NULL);
  518.  
  519.   reports.Info(TReports::VL_ASM1, "Starting assembler on %s", reports.Today());
  520.   reports.Info(TReports::VL_ASM1, "Assembling: %s\n\n", asm_source);
  521.   
  522.   PSource tmpP, objP;
  523.   strcpy(sourceFile,asm_source);
  524.   sprintf(tmpFileName,"%s/ava.%d",TMP_DIR, getpid());
  525.   char* fullstop = strrchr(sourceFile,'.');
  526.   if (outfile==NULL){
  527.     if (fullstop!=NULL){
  528.       strncpy(objectFileName,sourceFile,fullstop-sourceFile);
  529.       strcpy(&objectFileName[fullstop-sourceFile],".o");
  530.     }else{strcpy(objectFileName,sourceFile);strcat(objectFileName,".o");}
  531.   }else{strcpy(objectFileName, outfile);}
  532.     
  533.   /* do pass 1 to tmp file */
  534.   tmpP = new TFile(tmpFileName,"w+",true);
  535.   outfd=tmpP->stream();
  536.   syntax.Run();
  537.   if (reports.ErrorCount()>0){return;}
  538.     
  539.   /* do pass 2; rewind tmp and insert it to lexical analyzer */
  540.   tmpP->rew(); preproc.insert(tmpP,false);
  541.   objP = new TFile(objectFileName,"w"); outfd=objP->stream();
  542.   crc.Init();
  543.   
  544.   /* Primary Part of the Header */
  545.   createObjHeader();
  546.     
  547.   /* Partially Compiled Data */
  548.   outListing();
  549.   outAsmSource(sourceFile);
  550.     
  551.   /* PASS2 */
  552.    obji2objii(sourceFile);
  553.     
  554.   /* Secondary Part of the Header */
  555.   outTerminator();
  556.   obj_header_seek = ftell(outfd);
  557.   segment.saveSegments();
  558.   symbol.saveSymbols(); /* adds terminator between public/internal syms */
  559.   outHeaderIndex();
  560.   outEndofFile();
  561.     
  562.   segment.Report();
  563.   reports.Info(TReports::VL_ASM1, "Completed.\n\n");    
  564. }
  565.  
  566. /* Linker PASS1: Read header and segments of current file */
  567. void TObject::loadHeader(){
  568.   /* Check CRC and load header index */
  569.   char line_buf [LX_STRLEN], *reterr, *p;
  570.   long header_index=0;
  571.   crc.Init();
  572.   while((reterr=fgets(line_buf, LX_STRLEN-1, preproc.csrc->stream()))){
  573.     if (line_buf[0]==OBJ_HEADERIDX && line_buf[1]=='{'){
  574.       header_index = strtol(&line_buf[2], (char **)NULL, 16);
  575.     }
  576.     if (line_buf[0]==OBJ_ENDOFFILE && line_buf[1]=='{'){
  577.       unsigned long file_crc = strtoul(&line_buf[2], (char **)NULL, 16);
  578.       if (file_crc!=crc.Val()){
  579.         fprintf(stderr, "%s: CRC Error (0x%lx,0x%lx)\n" 
  580.        "Do you want to continue (enter y for yes, n for no):",
  581.       preproc.name(), file_crc, crc.Val());
  582.     scanf("%s", line_buf);
  583.     if (strcmp(line_buf,"y")!=0){throw generic_error("CRC Error.");}
  584.       }
  585.       break;
  586.     }
  587.     p = line_buf;
  588.     while(*p!=0){crc.Update(*p++);}
  589.   }
  590.   if (reterr==NULL){
  591.     throw syntax_error("File has no ending header?");
  592.   }
  593.   preproc.csrc->rew();
  594.  
  595.   /* Get AVA object info */
  596.   GET_TOKEN;
  597.   if (lxP->type!=TlxData::STRING || strcmp(lxP->string,obj_magic)){
  598.     throw syntax_error("This is not ava object file.");}
  599.   /* compare major numbers */
  600.   GET_TOKEN;
  601.   if (lxP->type!=TlxData::LVAL || lxP->lval!=OBJ_VERSION_MAJOR){
  602.     throw syntax_error("Object file is not compatabile with major version.");}
  603.   /* compare minor numbers - object file should have it lower or equal */
  604.   GET_TOKEN;
  605.   if (lxP->type!=TlxData::LVAL || lxP->lval>OBJ_VERSION_MINOR){
  606.     throw syntax_error("Object file is not compatabile with minor version.");}
  607.   GET_TOKEN;      /* new line, I assume */
  608.  
  609.   /* load device info */
  610.   keywords.Device();  
  611.  
  612.   /* remember current data and jump to header */
  613.   long tmpLineNumber = preproc.line();
  614.   long tmpOffset = ftell(preproc.csrc->stream());
  615.   preproc.seek(header_index,1);
  616.   
  617.   /* create segment translation table */
  618.   preproc.csrc->segP = new TSegTable();    
  619.       
  620.   /* load segments */  
  621.   while(lexer._gettoken()){
  622.     if (lxP->type==TlxData::NEWLINE){continue;}
  623.     if (lxP->string[0]==OBJ_TERMINATOR){break;}
  624.     if (lxP->type==TlxData::STRING && lxP->string[1]==0){
  625.  
  626.     switch(lxP->string[0]){
  627.       
  628.       /* operand: increment operand count per instruction */
  629.       case OBJ_OPERAND_CODE: 
  630.         loadOperand(true); break;
  631.  
  632.       case OBJ_OPERAND_QSTRING:    
  633.         loadStringOperand(); break;
  634.  
  635.       case OBJ_SEGMENT_INFO: /* segment */
  636.     segment.loadSegments((int)loadArgument()); 
  637.     if (operandStacksEmpty()==false){
  638.        throw syntax_error("Segment purely read its data:"
  639.          " stack is not empty.");
  640.      }
  641.     break;
  642.  
  643.       case OBJ_SYMBOL_INFO:
  644.         symbol.loadSymbols();
  645.     if (operandStacksEmpty()==false){
  646.       throw syntax_error("Symbol purely read its data: stack is not "
  647.         "empty.");
  648.     }
  649.     break;
  650.  
  651.       default:
  652.         throw syntax_error("Unsupported object directive: ",lxP->string);
  653.       }
  654.     }
  655.     else{
  656.       throw syntax_error("Load Header and Segments:"
  657.         " Object file is corrupted.");
  658.     }
  659.   }
  660.   /* restore initial condition */  
  661.   preproc.seek(tmpOffset, tmpLineNumber);
  662. }
  663.  
  664. /*
  665.   PARSER and GENERATOR from OBJ to EXECUTABLE FORMAT
  666. */
  667. void TObject::obj2exe(){
  668.   int segNo=SEGNUMBER_UNDEFINED;
  669.   int instr, key, i, cpylen = strlen(OBJ_COPY_OPERANDS);
  670.   long operand=0, currentLine=1, addr;
  671.   static char* copy_op = OBJ_COPY_OPERANDS;
  672.   char src [PPC_MAXFILELEN] = "";
  673.   bool enableSegment=true;
  674.   
  675.   /* halt on macros and non-external macros */
  676.   symbol.haltOnMacro();
  677.   syntax.haltOnInvalidMacros();
  678.   
  679.   /* disable listings by default */
  680.   reports.listing.Disable();  
  681.  
  682.   /* first call to lexer._gettoken removes #
  683.      from previously declared mem blocks
  684.   */ 
  685.   while(lexer._gettoken()){
  686.     if (lxP->type==TlxData::NEWLINE){continue;}
  687.     if (lxP->type==TlxData::STRING && lxP->string[1]==0){
  688.  
  689.       switch(lxP->string[0]){
  690.       
  691.       /* operand: increment operand count per instruction */
  692.       case OBJ_OPERAND_CODE: 
  693.         if (enableSegment==false){skipOperand();break;}
  694.         if (loadOperand(true)==false){
  695.       throw syntax_error("Undefined reference: ", gas.eqstr);}
  696.         break;
  697.  
  698.       case OBJ_OPERAND_QSTRING:    
  699.         if (enableSegment==false){skipOperand();break;}
  700.         loadStringOperand();
  701.     break;
  702.  
  703.       case OBJ_INSTRUCTION: /* instruction */
  704.         instr=(int)loadArgument();
  705.     if (enableSegment==false){break;}
  706.     preproc.mark(currentLine,src);
  707.     archp->Translate(instr);
  708.     if (operandStacksEmpty()==false){
  709.       throw syntax_error("obj2exe:instruction:"
  710.         " Operand stack is not empty.");
  711.     }
  712.         break;
  713.  
  714.       case OBJ_KEYWORD:
  715.         key=(int)loadArgument();
  716.     if (enableSegment==false){break;}
  717.     preproc.mark(currentLine,src);
  718.     keywords.Translate(key);
  719.     if (operandStacksEmpty()==false){
  720.       throw syntax_error("obj2exe:keyword: Operand stack is not empty.");}
  721.         break;
  722.  
  723.       case OBJ_SEGMENT: /* segment */
  724.         segNo = preproc.csrc->segP->seg[(int)loadArgument()].newNo;
  725.     enableSegment = segment.isEnabled(segNo);
  726.     seg_output = seg_output_table[segNo];
  727.     if (seg_output()==NULL){
  728.       throw generic_error("Internal Error: seg_output()==NULL");}
  729.     if (enableSegment==true){outSegment(segNo);}
  730.         break;
  731.  
  732.       case OBJ_OPERAND_PCMARKER: /* PC marker */
  733.         if (enableSegment==false){skipOperand();break;}
  734.         if (loadOperand(true)==false){
  735.       throw syntax_error("Undefined reference: ", gas.eqstr);}
  736.     outPCMarker(addr=popOperand(),segNo);
  737.     reports.listing.Address(addr);
  738.     break;
  739.  
  740.       case OBJ_SYMBOL_INFO: 
  741.         symbol.loadNonPublicSymbols();
  742.         break;
  743.  
  744.       case OBJ_ASMSOURCE:
  745.         loadStringOperand();
  746.     strcpy(src, popStringOperand());
  747.     outAsmSource(src);
  748.     reports.listing.Create(src);
  749.     break;
  750.  
  751.       case OBJ_ASMREF: /* assembler listing */
  752.         currentLine=loadArgument();
  753.     if (enableSegment){
  754.       reports.listing.GotoLine(currentLine);
  755.       outSrcLine(currentLine);
  756.     }
  757.     break;
  758.  
  759.       case OBJ_LISTING_ENABLED: reports.listing.Enable();break;
  760.       
  761.       case OBJ_TERMINATOR:
  762.       case OBJ_ENDOFFILE:
  763.         if (operandStacksEmpty()==false){
  764.       throw generic_error("OBJ_EOF: Operand stack is not empty.");}
  765.         return;
  766.  
  767.       default:
  768.         for (i=0;i<cpylen;i++){
  769.       if (lxP->string[0]==copy_op[i]){
  770.         operand=loadArgument();
  771.         if (uAsm_exe){break;}
  772.         if (enableSegment){outOperand(operand,copy_op[i]);break;}}
  773.     }
  774.     if (i==cpylen){
  775.           throw syntax_error("Unsupported object directive: ",lxP->string);}
  776.     break;
  777.       }
  778.     }
  779.     else if (lxP->type==TlxData::QSTRING){
  780.       if (enableSegment){
  781.         reports.listing.Codecat(lxP->string);
  782.     seg_output->Push(lxP->string);
  783. //    if (!uAsm_exe){CRCprintf(outfd,"\"%s\"\n",lxP->string);}
  784.       }
  785.     }
  786.     else{throw syntax_error("obj2exe: Object file is corrupted.");}
  787.   }
  788. }
  789.  
  790. void TObject::link(const char* outfile){
  791.   char exeFileName[PPC_MAXFILELEN];
  792.   {
  793.     reports.Info(TReports::VL_LINK1, "Starting linker on %s", reports.Today());
  794.         
  795.     if (reports.listing.IsEnabled()){
  796.       reports.Warnning("To generate listing files add -L switch to the "
  797.                        "assembler only.");}
  798.   
  799.     /* rotate files while loading header, segment and symbol info. */
  800.     do{loadHeader();}while(preproc.next());
  801.     reports.Info(TReports::VL_LINK1, "\n");
  802.     segment.fitter();
  803.     
  804.     /* update public for every file separately and report files */
  805.     reports.Info(TReports::VL_LINK1, "Linking:\n");
  806.     do{
  807.       reports.Info(TReports::VL_LINK1, " * %s\n",preproc.name());
  808.       segment.adjustSegments(); symbol.updatePublic();
  809.     }while(preproc.next());
  810.     reports.Info(TReports::VL_LINK1, "\n");
  811.     
  812.     /* Now we are ready to link the stuff. Prepeare files and go ... */
  813.     if (outfile==NULL){strcpy(exeFileName,DEFAULT_EXE);}
  814.     else{strcpy(exeFileName,outfile);}
  815.     
  816.     PSource exeP = new TFile(exeFileName, "w"); outfd=exeP->stream(); 
  817.     
  818.     createExeHeader();
  819.     CreateOutputBuffers();
  820.     do{
  821.       segment.adjustSegments();
  822.       obj2exe();
  823.       outTerminator();
  824.     }while(preproc.next()==true);
  825.     
  826.     /* FLUSH buffers */
  827.     for (int segcnt=0; segcnt<MAX_SEGMENTS; segcnt++){
  828.       if (seg_output_table[segcnt]()==NULL){continue;}
  829.       if (seg_output_table[segcnt]->Empty()){continue;}
  830.       seg_output_table[segcnt]->Flush(outfd);
  831.     }
  832.  
  833. // for non uAsm outputs ...    
  834. //    segment.saveSegments();
  835. //    symbol.saveSymbols();
  836.     outEndofFile();
  837.     reports.Info(TReports::VL_LINK1, "Completed.\n\n");
  838.   }  
  839. }
  840.  
  841.